

/*******************************************************
 * 函数名：cn_utf8_to_unicode
 * 描述  ：中文字符utf-8编码转unicode编码函数
 * 参数  ：
 *        @cInput     中文的utf-8编码值
 * 返回值：对于中文的unicode编码值
 **********************************************************/
uint16_t cn_utf8_to_unicode(const uint32_t cInput)
{
    // b1 表示UTF-8编码的pInput中的高字节, b2 表示次高字节, ...
    uint8_t b1, b2, b3;
    uint16_t cOutput = 0;
    b1 = (cInput & 0x000F0000) >> 16;
    b2 = (cInput & 0x00003F00) >> 8;
    b3 = (cInput & 0x0000003F);
    cOutput = (b1 << 12) + (b2 << 6) + b3;
    return cOutput;
}

/*******************************************************
 * 函数名：tickerCount
 * 描述  ：每隔设定时间递增
 * 参数  ：无
 * 返回值：无
 **********************************************************/
void tickerCount()
{
    count++;
    if (count == 9999) count = 0;  
}

/*******************************************************
 * 函数名：hsv2rgb
 * 描述  ：颜色转换方法
 * 参数  ：h s v
 * 返回值：rgb
 **********************************************************/
uint16_t hsv2rgb(uint16_t hue, uint8_t saturation, uint8_t value)
{
    uint8_t red = 0;
    uint8_t green = 0;
    uint8_t blue = 0;
    uint16_t hi = (hue / 60) % 6;
    uint16_t F = 100 * hue / 60 - 100 * hi;
    uint16_t P = value * (100 - saturation) / 100;
    uint16_t Q = value * (10000 - F * saturation) / 10000;
    uint16_t T = value * (10000 - saturation * (100 - F)) / 10000;
    if(hue == 0){
      return matrix.Color(255*value/100, 255*value/100, 255*value/100);
    }
    switch (hi)
    {
    case 0:
        red = value;
        green = T;
        blue = P;
        break;
    case 1:
        red = Q;
        green = value;
        blue = P;
        break;
    case 2:
        red = P;
        green = value;
        blue = T;
        break;
    case 3:
        red = P;
        green = Q;
        blue = value;
        break;
    case 4:
        red = T;
        green = P;
        blue = value;
        break;
    case 5:
        red = value;
        green = P;
        blue = Q;
        break;
    default:
        return matrix.Color(255, 0, 0);
    }
    red = red * 255 / 100;
    green = green * 255 / 100;
    blue = blue * 255 / 100;
    return matrix.Color(red, green, blue);
}

void drawFastXLine(int16_t x, int16_t y, int16_t h, uint16_t c){
  for(int i=x;i<x+h;i++){
    matrix.drawPixel(i,y,c);
  }
}

void drawFastYLine(int16_t x, int16_t y, int16_t h, int16_t c){
  for(int i=y;i<y+h;i++){
    matrix.drawPixel(x,i,c);
  }
}

// 显示WiFi连接完成动画
void showWiFiDoneAnimation( bool clear)
{
  for (int i = 0; i < 8; i++)
  {
    showWiFiConnectDone(i, true);
    delay(100);
  }
  delay(500);
}

// WiFi连接完成动画帧
void showWiFiConnectDone(int status, bool clear)
{
  if (clear)
  {
    matrix.clear();
  }
  switch (status)
  {
  case 7:
    matrix.drawPixel(27, 1, 0x07E0);
  case 6:
    matrix.drawPixel(26, 2, 0x07E0);
  case 5:
    matrix.drawPixel(25, 3, 0x07E0);
  case 4:
    matrix.drawPixel(24, 4, 0x07E0);
  case 3:
    matrix.drawPixel(23, 5, 0x07E0);
  case 2:
    matrix.drawPixel(22, 4, 0x07E0);
  case 1:
    matrix.drawPixel(21, 3, 0x07E0);
  case 0:
    // char wifi[] = "WiFi";
    // for (int i = 0; i < 4; i++)
    // {
    //   showCharacter(i*4+3, 1, (int)wifi[i], Apple4x6, matrix.Color(65,105,225));
    // }
    matrix.drawFastVLine(2,2,2,0xFFFF);
    matrix.drawFastVLine(3,4,2,0xFFFF);
    matrix.drawFastVLine(4,2,2,0xFFFF);
    matrix.drawFastVLine(5,4,2,0xFFFF);
    matrix.drawFastVLine(6,2,2,0xFFFF);
    matrix.drawPixel(8,2,0xFFFF);
    matrix.drawFastVLine(8,4,2,0xFFFF);
    matrix.fillRect(10,1,6,6,matrix.Color(255,0,0));
    matrix.drawFastVLine(11,2,4,0x0000);
    matrix.drawPixel(12,2,0x0000);
    matrix.drawPixel(12,4,0x0000);
    matrix.drawPixel(14,2,0x0000);
    matrix.drawFastVLine(14,4,2,0x0000);
    break;
  }
  matrix.show();
}

// 显示固件信息
void showFirmwareInfo(int x, int y, bool clear)
{
  for (int i = 33; i > 1; i--)
  {
    if (clear)
    {
      matrix.clear();
    }
    showCharacter(i+1, y, (int)XMatrix[0], Apple4x6, matrix.Color(255,0,0));
    showCharacter(i+5, y, (int)XMatrix[1], Apple4x6, matrix.Color(255,127,0));
    showCharacter(i+9, y, (int)XMatrix[2], Apple4x6, matrix.Color(255, 255, 0));
    showCharacter(i+13, y, (int)XMatrix[3], Apple4x6, matrix.Color(0, 255, 0));
    showCharacter(i+17, y, (int)XMatrix[4], Apple4x6, matrix.Color(0, 255, 255));
    showCharacter(i+21, y, (int)XMatrix[5], Apple4x6, matrix.Color(46, 43, 95));
    showCharacter(i+25, y, (int)XMatrix[6], Apple4x6, matrix.Color(139, 0, 255));
    matrix.show();
    delay(16);
  }
  delay(1000);
}

void showFirmwareInfoEnd()
{
  int i = 1;
  for (int y = 0; y < 8; y++)
  {
    matrix.clear();
    showCharacter(i+1, y, (int)XMatrix[0], Apple4x6, matrix.Color(255,0,0));
    showCharacter(i+5, y, (int)XMatrix[1], Apple4x6, matrix.Color(255,127,0));
    showCharacter(i+9, y, (int)XMatrix[2], Apple4x6, matrix.Color(255, 255, 0));
    showCharacter(i+13, y, (int)XMatrix[3], Apple4x6, matrix.Color(0, 255, 0));
    showCharacter(i+17, y, (int)XMatrix[4], Apple4x6, matrix.Color(0, 255, 255));
    showCharacter(i+21, y, (int)XMatrix[5], Apple4x6, matrix.Color(46, 43, 95));
    showCharacter(i+25, y, (int)XMatrix[6], Apple4x6, matrix.Color(139, 0, 255));
    matrix.show();
    delay(20);
  }
  matrix.clear();
}

/*******************************************************
 * 函数名：showCharacter
 * 描述  ：显示单个字符
 * 参数  ：
 *        @char_x     字符左上角x坐标
 *        @char_y     字符左上角y坐标
 *        @c          字符编码
 *        @charfont   字体
 *        @showColor  显示的颜色
 * 返回值：无
 **********************************************************/
void showCharacter(int char_x, int char_y, int c, int charfont, uint16_t showColor)
{
    int i, x, y, characterSpace;
    unsigned char line;
    unsigned short ct;

    const unsigned char *cb = fontattribute[charfont].font_bitmap;
    const unsigned char *ci = fontattribute[charfont].font_index;
    int len = fontattribute[charfont].font_num;
    int lx = fontattribute[charfont].font_width;
    int ly = fontattribute[charfont].font_height;

    if (charfont == Cnfont8x8 && c > 0xFF) //中文字体中的非英文字体
        ct = cn_utf8_to_unicode(c);
    else
        ct = (unsigned short)c;

    for (i = 0; i < len; i++)
    {
        if (charfont == Cnfont8x8) //中文编码为8字节，不方便用放flash，内存充足，因此放内存中。
        {
            if (Cnfont_index[i] == ct)
            {
                characterSpace = i;
                break;
            }
        }
        else
        {
            if (pgm_read_byte(ci + i) == ct) // ci[i] == ct
            {
                characterSpace = i;
                break;
            }
        }
    }
    if (i == len)
        characterSpace = 1; //空白符

    for (y = 0; y < ly; y++)
    {
        // line = cb[ly * characterSpace + y];
        line = pgm_read_byte(cb + (ly * characterSpace + y));
        for (x = 0; x < lx; x++)
        {
            if(((line >> (7 - x)) & 0x01) != 0){
                matrix.drawPixel(char_x + x, char_y + y,showColor);
            }else{
                matrix.drawPixel(char_x + x, char_y + y,matrix.Color( 0, 0, 0));
            }
        }
    }
}


/*******************************************************
 * 函数名：showStringSlip
 * 描述  ：滚动显示字符串
 * 参数  ：
 *        @char_x     字符串起始左上角x坐标
 *        @char_y     字符串起始左上角y坐标
 *        @charfont   字体
 *        @str        字符串
 *        @len        字符串长度
 * 返回值：无
 **********************************************************/
void showStringSlip(int char_x, int char_y, int charfont, char *str, int len, uint16_t showColor)
{
    count++;
    int num = len/3;
    if (count > (64/16))
    {
        if(wordshow_i > (8*num-31+char_x))
        {
            wordshow_i = 0;
        }
        wordshow_i++;
        count = 0;
    }
    cnstr_p = 0;
    for (int j = 0; j < num; j++)
    {
        if (charfont == Cnfont8x8)
        {   
            cnstr_pos[j] = cnstr_l+j*8;
            if ((uint8_t)str[cnstr_p] < 0xE0) //非中文
            {
                showCharacter(char_x - wordshow_i + cnstr_pos[j], char_y, (int)str[cnstr_p], charfont, showColor);
                cnstr_p += 1; //一个英文字符1字节
            }
            else
            {
                showCharacter(char_x - wordshow_i + cnstr_pos[j], char_y, (int)((str[cnstr_p] << 16) + (str[cnstr_p + 1] << 8) + str[cnstr_p + 2]), charfont, showColor);
                cnstr_p += 3; //一个中文字符3字节 
            }
            Serial.print("j:");
            Serial.println(j);
            Serial.print("cnstr_p:");
            Serial.println(cnstr_p);
            Serial.print("x:");
            Serial.println(char_x - wordshow_i + cnstr_pos[j]);
        }
        else
            showCharacter(char_x - wordshow_i + j * 4, char_y, str[j], charfont, showColor);
    } 
}

/*******************************************************
 * 函数名：showStringAlways
 * 描述  ：固定显示字符串，默认中文
 * 参数  ：
 *        @charfont   字体
 *        @str        字符串
 *        @len        字符串长度
 * 返回值：无
 **********************************************************/
void showStringAlways(int charfont, char *str, int len, uint16_t showColor)
{
  int num = len/3;
  //Serial.println(num);
  if (charfont == Cnfont8x8)
  {   
    switch(num){
      case 1:
        showCharacter(19+GlobalX, 0+GlobalY, (int)((str[0] << 16) + (str[1] << 8) + str[2]), charfont, showColor);
        break;
      case 2:
        showCharacter(12+GlobalX, 0+GlobalY, (int)((str[0] << 16) + (str[1] << 8) + str[2]), Cnfont8x8, showColor);
        showCharacter(21+GlobalX, 0+GlobalY, (int)((str[3] << 16) + (str[4] << 8) + str[5]), Cnfont8x8, showColor);
        break;
      case 3:
        showCharacter(8+GlobalX, 0+GlobalY, (int)((str[0] << 16) + (str[1] << 8) + str[2]), Cnfont8x8, showColor);
        showCharacter(16+GlobalX, 0+GlobalY, (int)((str[3] << 16) + (str[4] << 8) + str[5]), Cnfont8x8, showColor);
        showCharacter(24+GlobalX, 0+GlobalY, (int)((str[6] << 16) + (str[7] << 8) + str[8]), Cnfont8x8, showColor);
        break;
    }
  }
}

/*******************************************************
 * 函数名：showStringAlways
 * 描述  ：固定显示字符串，默认中文
 * 参数  ：
 *        @char_x     字符串起始左上角x坐标
 *        @char_y     字符串起始左上角y坐标
 *        @charfont   字体
 *        @str        字符串
 *        @len        字符串长度
 * 返回值：无
 **********************************************************/
void showString(int char_x, int char_y, int charfont, char *str, int len, uint16_t showColor)
{
  int num = len/3;
  //Serial.println(num);
  if (charfont == Cnfont8x8)
  {   
    switch(num){
      case 1:
        showCharacter(char_x+GlobalX, char_y+GlobalY, (int)((str[0] << 16) + (str[1] << 8) + str[2]), charfont, showColor);
        break;
      case 2:
        showCharacter(char_x+GlobalX, char_y+GlobalY, (int)((str[0] << 16) + (str[1] << 8) + str[2]), Cnfont8x8, showColor);
        showCharacter(char_x+8+GlobalX, char_y+GlobalY, (int)((str[3] << 16) + (str[4] << 8) + str[5]), Cnfont8x8, showColor);
        break;
      case 3:
        showCharacter(char_x+GlobalX, char_y+GlobalY, (int)((str[0] << 16) + (str[1] << 8) + str[2]), Cnfont8x8, showColor);
        showCharacter(char_x+8+GlobalX, char_y+GlobalY, (int)((str[3] << 16) + (str[4] << 8) + str[5]), Cnfont8x8, showColor);
        showCharacter(char_x+16+GlobalX, char_y+GlobalY, (int)((str[6] << 16) + (str[7] << 8) + str[8]), Cnfont8x8, showColor);
        break;
    }
  }
}

void showbitnumber(int number, int xlength, int ylength, int x, int y, uint16_t colorxy){
  String numStr = String(number);
  if(number<10){
    showbitmap(bitdata20[(int)(0)],xlength,ylength, x, y, colorxy);
    showbitmap(bitdata20[(int)((String(numStr.charAt(0)).toInt() + 1) - 1)],xlength,ylength, x+4, y, colorxy);
  }else if(number<100){
    showbitmap(bitdata20[(int)((String(numStr.charAt(0)).toInt() + 1) - 1)],xlength,ylength, x, y, colorxy);
    showbitmap(bitdata20[(int)((String(numStr.charAt(1)).toInt() + 1) - 1)],xlength,ylength, x+4, y, colorxy);
  }else if(number<1000){
    showbitmap(bitdata20[(int)((String(numStr.charAt(0)).toInt() + 1) - 1)],xlength,ylength, x, y, colorxy);
    showbitmap(bitdata20[(int)((String(numStr.charAt(1)).toInt() + 1) - 1)],xlength,ylength, x+4, y, colorxy);
    showbitmap(bitdata20[(int)((String(numStr.charAt(2)).toInt() + 1) - 1)],xlength,ylength, x+8, y, colorxy);
  }else if(number<10000){
    showbitmap(bitdata20[(int)((String(numStr.charAt(0)).toInt() + 1) - 1)],xlength,ylength, x, y, colorxy);
    showbitmap(bitdata20[(int)((String(numStr.charAt(1)).toInt() + 1) - 1)],xlength,ylength, x+4, y, colorxy);
    showbitmap(bitdata20[(int)((String(numStr.charAt(2)).toInt() + 1) - 1)],xlength,ylength, x+8, y, colorxy);
    showbitmap(bitdata20[(int)((String(numStr.charAt(3)).toInt() + 1) - 1)],xlength,ylength, x+12, y, colorxy);
  }else if(number<100000){
    showbitmap(bitdata20[(int)((String(numStr.charAt(0)).toInt() + 1) - 1)],xlength,ylength, x, y, colorxy);
    showbitmap(bitdata20[(int)((String(numStr.charAt(1)).toInt() + 1) - 1)],xlength,ylength, x+4, y, colorxy);
    showbitmap(bitdata20[(int)((String(numStr.charAt(2)).toInt() + 1) - 1)],xlength,ylength, x+8, y, colorxy);
    showbitmap(bitdata20[(int)((String(numStr.charAt(3)).toInt() + 1) - 1)],xlength,ylength, x+12, y, colorxy);
    showbitmap(bitdata20[(int)((String(numStr.charAt(4)).toInt() + 1) - 1)],xlength,ylength, x+16, y, colorxy);
  }else if(number<1000000){
    showbitmap(bitdata20[(int)((String(numStr.charAt(0)).toInt() + 1) - 1)],xlength,ylength, x, y, colorxy);
    showbitmap(bitdata20[(int)((String(numStr.charAt(1)).toInt() + 1) - 1)],xlength,ylength, x+4, y, colorxy);
    showbitmap(bitdata20[(int)((String(numStr.charAt(2)).toInt() + 1) - 1)],xlength,ylength, x+8, y, colorxy);
    showbitmap(bitdata20[(int)((String(numStr.charAt(3)).toInt() + 1) - 1)],xlength,ylength, x+12, y, colorxy);
    showbitmap(bitdata20[(int)((String(numStr.charAt(4)).toInt() + 1) - 1)],xlength,ylength, x+16, y, colorxy);
    showbitmap(bitdata20[(int)((String(numStr.charAt(5)).toInt() + 1) - 1)],xlength,ylength, x+20, y, colorxy);
  }
}

void showbitmap(String bitrgbstr, int xlength, int ylength, int x, int y, uint16_t colorxy) {
  //Serial.println("bitrgbstr = " + bitrgbstr);
  for (int i = x; i < x+(xlength); i = i + (1)) {
    for(int j = y; j < y+(ylength); j = j + (1)){
      if (String(bitrgbstr.charAt(((j-y)*xlength+i-x))).toInt() != 0) {
        matrix.drawPixel(i,j,colorxy);
      } else {
        matrix.drawPixel(i,j,matrix.Color( 0, 0, 0));
      }
    }
  }
}

//显示时钟的冒号方法
void showColon(int x,int y,bool l,uint16_t colorxy){
  String pstr = "101";
  for(int j = y; j < y+3; j = j + (1)){
    if (String(pstr.charAt(j-y)).toInt() != 0) {
      if(l){
        matrix.drawPixel(x,j,colorxy);
      }else{
        matrix.drawPixel(x,j,matrix.Color(0, 0, 0));
      }
    } else {
      matrix.drawPixel(x,j,matrix.Color(0, 0, 0));
    }
  }
}

//配置同步方法
void configSync(uint8_t num){
  DynamicJsonDocument myObject(256);
  myObject["mode"] = Mode;
  myObject["brightNess"] = brightnessNow;
  myObject["huea"] = hue;
  myObject["hued"] = hue;
  myObject["huem"] = huem;
  myObject["hues"] = hues;
  myObject["huew"] = huew;
  myObject["hueb"] = hueb;
  myObject["clockMode"] = clockMode;
  myObject["dateMode"] = dateMode;
  myObject["cityCode"] = String(CITY_CODE).substring(0,EEPROM_CITY_CODE_LEN);
  myObject["yyKey"] = String(YY_KEY).substring(0,EEPROM_KEY_LEN);
  myObject["bFansMode"] = bFansMode;
  myObject["loopMode"] = loopMode;
  String output;
  serializeJson(myObject, output);
  Serial.print(output);
  webSocket.sendTXT(num, output);
}

//切换模式风格方法
void switchLoopMode(int oldMode, int newMode){
  switch(loopMode){
    case 1://上下切换
      for(int i=0;i<9;i++){
       matrix.clear();
       GlobalY = -i;
       switchMode(false,oldMode);
       GlobalY = 8-i;
       switchMode(false,newMode);
       matrix.show();
       delay(16);
      }
      break;
    case 2://渐隐渐显
      for(int i=0;i<40;i++){
        matrix.clear();
        if(i<20){
          if(brightnessNow<20){
            if(brightnessNow>i){
              matrix.setBrightness(brightnessNow-i);
            }else{
              matrix.setBrightness(0);
            }
          }else{
            matrix.setBrightness(brightnessNow-brightnessNow/20*(i+1));
          }
          switchMode(false,oldMode);
        }else{
          if(brightnessNow<20){
            if(brightnessNow>(i-20)){
              matrix.setBrightness(i-20);
            }else{
              matrix.setBrightness(brightnessNow);
            }
          }else{
            matrix.setBrightness(brightnessNow/20*(i-19));
          }
          switchMode(false,newMode);
        }
        matrix.show();
        delay(16);
      }
      break;    
  }
}

//获取粉丝数
void ParseFans(String url){
  if(loopChangeStatus) return;
  DynamicJsonDocument doc(1024);  //分配内存
  http.begin(url);    //请求网址
  int httpGet = http.GET();    //获得服务器状态码
  if(httpGet > 0)
  {
    Serial.printf("HTTPGET is %d",httpGet);    //打印服务器状态码
    if(httpGet == HTTP_CODE_OK)    //判断是否请求成功
    {
      String json = http.getString();    //获得响应体信息
      Serial.println(json);    //打印响应体信息
      deserializeJson(doc, json);    //Json解析
      Fansnumber = doc["data"]["follower"];    //获得粉丝数，整形
    }
    else
    {
      Serial.printf("ERROR1!!");
    }
  }
  else
  {
    Serial.printf("ERROR2!!");
  }
  http.end();
}

//B站图案
void BPattern(int ani){
  String  pstr[3] = {
    "0100001000100100011111101000000110100101101001011000000101111110",
    "0100001000100100011111101000000110000001100000011000000101111110",
    "0100001000100100011111101000000110100101100000011000000101111110"};
  for (int i = 0; i < 8; i = i + (1)) {
    for(int j = 0; j < 8; j = j + (1)){
      if (String(pstr[ani].charAt((j*8+i))).toInt() != 0) {
        matrix.drawPixel(i+GlobalX,j+GlobalY,matrix.Color(0,191,255));
      } else {
        matrix.drawPixel(i+GlobalX,j+GlobalY,matrix.Color(0, 0, 0));
      }
    }
  }
}

void showLoading(){
  showCharacter(11+GlobalX, 1+GlobalY, (int)'G', Apple4x6, matrix.Color(255,0,0));
  showCharacter(14+GlobalX, 1+GlobalY, (int)'e', Apple4x6, matrix.Color(255,127,0));
  showCharacter(17+GlobalX, 1+GlobalY, (int)'t', Apple4x6, matrix.Color(255, 255, 0));
  showCharacter(20+GlobalX, 1+GlobalY, (int)'i', Apple4x6, matrix.Color(0, 255, 0));
  showCharacter(23+GlobalX, 1+GlobalY, (int)'n', Apple4x6, matrix.Color(0, 255, 255));
  showCharacter(26+GlobalX, 1+GlobalY, (int)'g', Apple4x6, matrix.Color(139, 0, 255));
}

//展示粉丝数
void showBFansNumber(){
  int rangK = 0;
  switch(bFansMode){
    case 1:
      rangK = 0;
      break;
    case 2:
      rangK = 65;
      break;
  }
  int sx = 29+GlobalX;
  int sy = 2+GlobalY;
  if(Fansnumber<0){
    showLoading();
  }else if(Fansnumber<10){
    showCharacter(sx, sy, Fansnumber + 48, Clock3x5, hsv2rgb(hueLoop(hueb+rangK), saturation, value));
  }else if(Fansnumber<100){
    showCharacter(sx, sy, Fansnumber%10 + 48, Clock3x5, hsv2rgb(hueLoop(hueb+rangK), saturation, value));
    showCharacter(sx-4, sy, Fansnumber/10 + 48, Clock3x5, hsv2rgb(hueLoop(hueb+rangK*2), saturation, value));
  }else if (Fansnumber<1000){
    showCharacter(sx, sy, Fansnumber%10 + 48, Clock3x5, hsv2rgb(hueLoop(hueb+rangK), saturation, value));
    showCharacter(sx-4, sy, Fansnumber/10%10 + 48, Clock3x5, hsv2rgb(hueLoop(hueb+rangK*2), saturation, value));
    showCharacter(sx-8, sy, Fansnumber/100 + 48, Clock3x5, hsv2rgb(hueLoop(hueb+rangK*3), saturation, value));
  }else if (Fansnumber<10000){
    showCharacter(sx, sy, Fansnumber%10 + 48, Clock3x5, hsv2rgb(hueLoop(hueb+rangK), saturation, value));
    showCharacter(sx-4, sy, Fansnumber/10%10 + 48, Clock3x5, hsv2rgb(hueLoop(hueb+rangK*2), saturation, value));
    showCharacter(sx-8, sy, Fansnumber/100%10 + 48, Clock3x5, hsv2rgb(hueLoop(hueb+rangK*3), saturation, value));
    showCharacter(sx-12, sy, Fansnumber/1000 + 48, Clock3x5, hsv2rgb(hueLoop(hueb+rangK*4), saturation, value));
  }else if (Fansnumber<100000){
    showCharacter(sx, sy, Fansnumber%10 + 48, Clock3x5, hsv2rgb(hueLoop(hueb+rangK), saturation, value));
    showCharacter(sx-4, sy, Fansnumber/10%10 + 48, Clock3x5, hsv2rgb(hueLoop(hueb+rangK*2), saturation, value));
    showCharacter(sx-8, sy, Fansnumber/100%10 + 48, Clock3x5, hsv2rgb(hueLoop(hueb+rangK*3), saturation, value));
    showCharacter(sx-12, sy, Fansnumber/1000%10 + 48, Clock3x5, hsv2rgb(hueLoop(hueb+rangK*4), saturation, value));
    showCharacter(sx-16, sy, Fansnumber/10000 + 48, Clock3x5, hsv2rgb(hueLoop(hueb+rangK*5), saturation, value));
  }else if (Fansnumber<1000000){
    showCharacter(sx, sy, Fansnumber%10 + 48, Clock3x5, hsv2rgb(hueLoop(hueb+rangK), saturation, value));
    showCharacter(sx-4, sy, Fansnumber/10%10 + 48, Clock3x5, hsv2rgb(hueLoop(hueb+rangK*2), saturation, value));
    showCharacter(sx-8, sy, Fansnumber/100%10 + 48, Clock3x5, hsv2rgb(hueLoop(hueb+rangK*3), saturation, value));
    showCharacter(sx-12, sy, Fansnumber/1000%10 + 48, Clock3x5, hsv2rgb(hueLoop(hueb+rangK*4), saturation, value));
    showCharacter(sx-16, sy, Fansnumber/10000%10 + 48, Clock3x5, hsv2rgb(hueLoop(hueb+rangK*5), saturation, value));
    showCharacter(sx-20, sy, Fansnumber/100000 + 48, Clock3x5, hsv2rgb(hueLoop(hueb+rangK*6), saturation, value));
  }else{
    showCharacter(sx, sy, 9 + 48, Clock3x5, hsv2rgb(hueLoop(hueb+rangK), saturation, value));
    showCharacter(sx-4, sy, 9 + 48, Clock3x5, hsv2rgb(hueLoop(hueb+rangK*2), saturation, value));
    showCharacter(sx-8, sy, 9 + 48, Clock3x5, hsv2rgb(hueLoop(hueb+rangK*3), saturation, value));
    showCharacter(sx-12, sy, 9 + 48, Clock3x5, hsv2rgb(hueLoop(hueb+rangK*4), saturation, value));
    showCharacter(sx-16, sy, 9 + 48, Clock3x5, hsv2rgb(hueLoop(hueb+rangK*5), saturation, value));
    showCharacter(sx-20, sy, 9 + 48, Clock3x5, hsv2rgb(hueLoop(hueb+rangK*6), saturation, value));
  }
}

int hueLoop(int h){
  return h>360? h-360:h;
}

//获取天气实况
void weatherNow(String url){
  if(loopChangeStatus) return;
  DynamicJsonDocument doc(1024);  //分配内存
  http.begin(url);    //请求网址

  int httpGet = http.GET();    //获得服务器状态码
  if(httpGet > 0)
  {
    Serial.printf("HTTPGET is %d",httpGet);    //打印服务器状态码
    if(httpGet == HTTP_CODE_OK)    //判断是否请求成功
    {
      String json = http.getString();    //获得响应体信息
      Serial.println(json);    //打印响应体信息
      deserializeJson(doc, json);    //Json解析
      String temp = doc["data"]["qw"];
      String hum = doc["data"]["sd"];
      String tq = doc["data"]["tq"];
      String numtq = doc["data"]["numtq"];
      hum_read = hum;
      temp_read = temp;
      tq_code = numtq;
      strcpy(tq_str,tq.c_str());
      tq_len = tq.length();
//      Serial.print("温度");
//      Serial.println(temp_read);
//      Serial.print("湿度");
//      Serial.println(hum_read);
//      Serial.println(tq_str);
    }
    else
    {
      Serial.printf("ERROR1!!");
    }
  }
  else
  {
    Serial.printf("ERROR2!!");
  }
  http.end();
}

//a写入字符串长度，b是起始位，str为要保存的字符串
void Write_String(int a,int b,String str){
  EEPROM.write(a, str.length());//EEPROM第a位，写入str字符串的长度
  //把str所有数据逐个保存在EEPROM
  for (int i = 0; i < str.length(); i++){
    EEPROM.write(b + i, str[i]);
  }
  EEPROM.commit();
}
//a位是字符串长度，b是起始位
String Read_String(int a, int b){ 
  String data = "";
  //从EEPROM中逐个取出每一位的值，并链接
  for (int i = 0; i < a; i++){
    data += char(EEPROM.read(b + i));
  }
  return data;
}

/*******************************************************
 * 函数名：handleSettingMessage
 * 描述  ：文字配置信息处理，在网页采用json格式发送配置信息，因此用json库进行处理
 * 参数  ：无
 * 返回值：无
 **********************************************************/
void handleSettingMessage()
{
    // size_t inputLength; (optional)

    StaticJsonDocument<512> doc;
    DeserializationError error = deserializeJson(doc, settingMessage);

    if (error) {
    Serial.print(F("deserializeJson() failed: "));
    Serial.println(error.f_str());
    return;
    }

    String city = doc["city"];
    String key = doc["key"];
    Serial.print("city id:");
    Serial.println(city);
    Serial.print("yy key:");
    Serial.println(key);
    if(city.length() == EEPROM_CITY_CODE_LEN){
      CITY_CODE = city;
    }
    if(key.length() == EEPROM_KEY_LEN){
      YY_KEY = key;
    }
    configSave();
}
